unit MapBuffer;

interface

uses
  Winapi.Windows, System.Contnrs, System.Classes, System.SysUtils,
  MemBuffer, CriticalSection;

type
  (* TDIBufferNode节点 *)
  PTIBufferNode = ^TIBufferNode;
  TIBufferNode = record
    MapID:  Cardinal;            (* MapID           *)
    IsUsed: Boolean;          (* 是否为有效节点  *)
    Buffer: TIBuffer;        (* TDIBuffer       *)
  end;
  //动态缓存池(可回收不再使用的缓存对象入TQueue,分配使用的缓存对象入TList)
  //与PoolBuffer构成固定大小的缓存池,可动态管理缓存对象
  TIMapBuffer = class
  private
    FBuckets:       TList;            (* 上下文数组      *)
    PoolBuckets:    TQueue;           (* 空闲节点        *)
    ActiveCount:    Cardinal;            (* Map中活动节点数 *)
    BufferCount:    Cardinal;            (* Map中总数量     *)
    FMapBufferLock:  TCriticalSection; (* 锁              *)
  public
    (* 增加DIBuffer到列表           *)
    function AddBuffer(FBuffer: TIBuffer): Boolean;
    (* 把DIBuffer从列表中删除       *)
    function RemoveBuffer(FBuffer: TIBuffer): Boolean;
    (* 释放所有DIBuffer             *)
    procedure FreeBuffers;
    (* 得到活动DIBuffer总数量       *)
    function GetActiveBufferCount: Cardinal;
    (* 得到池内DIBuffer总数量       *)
    function GetBufferCount: Integer;
  published
    property MapBufferLock: TCriticalSection read FMapBufferLock write FMapBufferLock;
    property Buckets: TList read FBuckets write FBuckets;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

constructor TIMapBuffer.Create;
begin
  inherited Create;
  ActiveCount := 0;
  BufferCount := 0;
  PoolBuckets := TQueue.Create;
  FBuckets := TList.Create;
  FMapBufferLock := TCriticalSection.Create;
  FMapBufferLock.SetLockName('TIMapBuffer');
end;

destructor TIMapBuffer.Destroy;
var
  i: Integer;
begin
  FreeBuffers;
  MapBufferLock.Lock;
  for i := FBuckets.Count - 1 downto 0 do
    Dispose(FBuckets[i]);
  MapBufferLock.UnLock;
  FreeAndNil(FBuckets);
  FreeAndNil(PoolBuckets);
  FreeAndNil(FMapBufferLock);
  inherited Destroy;
end;

function TIMapBuffer.GetActiveBufferCount: Cardinal;
begin
  Result := ActiveCount;
end;

function TIMapBuffer.GetBufferCount: Integer;
begin
  Result := BufferCount;
end;

function TIMapBuffer.AddBuffer(FBuffer: TIBuffer): Boolean;
var
  pNode: PTIBufferNode;
begin
  Result := False;
  if not Assigned(FBuffer) then Exit;
  MapBufferLock.Lock;
  try
    if PoolBuckets.Count > 0 then
      begin
        pNode := PoolBuckets.Pop;
        pNode^.IsUsed := True;
        pNode^.Buffer := FBuffer;
        FBuffer.MapID := pNode^.MapID;
        Inc(ActiveCount);
      end
    else
      begin
        New(pNode);
        pNode^.Buffer := FBuffer;
        pNode^.IsUsed := True;
        pNode^.MapID := BufferCount;
        FBuffer.MapID := BufferCount;
        Inc(ActiveCount);
        Inc(BufferCount);
        FBuckets.Add(pNode);
      end;
    Result := True;
  finally
    MapBufferLock.UnLock;
  end;
end;

function TIMapBuffer.RemoveBuffer(FBuffer: TIBuffer): Boolean;
begin
  Result := False;
  if not Assigned(FBuffer) then Exit;
  MapBufferLock.Lock;
  try
    if not (FBuffer.MapID >= BufferCount) then
      begin
        if PTIBufferNode(FBuckets[FBuffer.MapID])^.IsUsed then
          begin
            PTIBufferNode(FBuckets[FBuffer.MapID])^.Buffer := nil;
            PTIBufferNode(FBuckets[FBuffer.MapID])^.IsUsed := False;
            PoolBuckets.Push(PTIBufferNode(FBuckets[FBuffer.MapID]));
            Dec(ActiveCount);
            Result := True;
          end
        else
        begin
          {$IFDEF _ICOP_DEBUGERR}
           _GlobalLogger.AppendErrorLogMessage('RemoveDIBuffer失败, MapID: %d, 活动Count: %d.',
            [ FBuffer.m_MapID, m_nActiveCount]);
          {$ENDIF}
        end;
      end
    else
      begin
        {$IFDEF _ICOP_DEBUGERR}
        _GlobalLogger.AppendErrorLogMessage('RemoveDIBuffer错误FBuffer.m_MapID >= m_nBufferCount, MapID: %d, Count: %d.',
          [FBuffer.m_MapID, m_nBufferCount]);
        {$ENDIF}
      end;
  finally
    MapBufferLock.UnLock;
  end;
end;

procedure TIMapBuffer.FreeBuffers;
var
  i: Integer;
begin
  MapBufferLock.Lock;
  try
    for i := 0 to FBuckets.Count - 1 do
    begin
      if ((PTIBufferNode(FBuckets[i])^.IsUsed) and
        (PTIBufferNode(FBuckets[i])^.Buffer <> nil)) then
      begin
        FreeAndNil(PTIBufferNode(FBuckets[i])^.Buffer);
        PTIBufferNode(FBuckets[i])^.IsUsed := False;
        PTIBufferNode(FBuckets[i])^.Buffer := nil;
        Dec(ActiveCount);
      end;
    end;
  finally
    MapBufferLock.UnLock;
  end;
end;

end.


